package com.smart.service.util.seteB;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import com.smart.service.util.UtilCard;
import com.smart.service.util.exception.CardException;


/**
 * Implementação orientada a objetos cuja implementação parece com a do 
 * design pattern TemplateMethod
 * @author bruno
 *
 */
public abstract class CardValidator7B {
	
	
	public boolean validate(String numero, String validade) throws CardException{
		
		String formatado =  preValidate(numero, validade);
		
		validateNumber(formatado);
		
		posValidation(formatado);
		
		return true;
	}
	
	private boolean posValidation(String formatado) throws CardException {
		// ----- NÚMERO -----
		// fórmula de LUHN (http://www.merriampark.com/anatomycc.htm)
		int soma = 0;
		int digito = 0;
		int somafim = 0;
		boolean multiplica = false;
		for (int i = formatado.length() - 1; i >= 0; i--) {
			digito = Integer.parseInt(formatado.substring(i, i + 1));
			if (multiplica) {
				somafim = digito * 2;
				if (somafim > 9) {
					somafim -= 9;
				}
			} else {
				somafim = digito;
			}
			soma += somafim;
			multiplica = !multiplica;
		}
		int resto = soma % 10;
		assert resto == 0 : "soma = " + soma;
		if (resto == 0) {
			return true;
		} else {
			throw new CardException(UtilCard.CARTAO_ERRO);
		}
	}

	
	private String preValidate(String numero, String validade) throws CardException {
		boolean validadeOK = false;
		// ----- VALIDADE -----
		Date dataValidade = null;
		try {
			dataValidade = new SimpleDateFormat("MM/yyyy").parse(validade);
		} catch (ParseException e) {
			throw new CardException(UtilCard.CARTAO_ERRO);
		}
		Calendar calValidade = new GregorianCalendar();
		calValidade.setTime(dataValidade);
		// apenas mês e ano são utilizados na validação
		Calendar calTemp = new GregorianCalendar();
		Calendar calHoje = (GregorianCalendar) calValidade.clone();
		calHoje.set(Calendar.MONTH, calTemp.get(Calendar.MONTH));
		calHoje.set(Calendar.YEAR, calTemp.get(Calendar.YEAR));
		validadeOK = calHoje.before(calValidade);
		if (!validadeOK) {
			throw new CardException(UtilCard.CARTAO_ERRO);
		}

		// ---- PREFIXO E TAMANHO -----
		String formatado = "";
		// remove caracteres não-numéricos
		for (int i = 0; i < numero.length(); i++) {
			char c = numero.charAt(i);
			if (Character.isDigit(c)) {
				formatado += c;
			}
		}
		return formatado;
	}

	protected abstract boolean validateNumber(String numero) throws CardException ;
	
}
